<?php
/**
 * Created by PhpStorm.
 * User: shooke
 * Date: 17-2-15
 * Time: 上午10:24
 */

namespace corephp\db\query;

/**
 * mysql查询解析类
 * 需要实现解析接口的方法
 * @package corephp\db\query
 */
class Mysql extends SqlAbstract implements ParseQueryInterface
{
    /**
     * 查询参数索引 query param index
     * @var int
     */
    protected $qpi = 0;
    public function insert()
    {
        $params = [];
        $column = [];
        $placeholder = '';
        $first = current($this->data);
        if(is_array($first)){
            $field = implode(',',array_keys($first));
            foreach ($this->data as $array){
                foreach ($array as $value){
                    $key = ":qpi{$this->qpi}";
                    $params[$key] = $value;
                    $temp[] = $key;
                    $this->qpi++;
                }
                $column[] = "(".implode(',',$temp).")";
            }
            $placeholder = implode(',',$column);
        }else{
            $field = implode(',',array_keys($this->data));
            foreach ($this->data as $value){
                $key = ":qpi{$this->qpi}";
                $params[$key] = $value;
                $column[] = $key;
                $this->qpi++;
            }
            $placeholder = "(".implode(',',$column).")";
        }
        $table = $this->parseFrom();
        $sql  = "INSERT INTO {$table} ({$field}) VALUES {$placeholder}";
        return [
            'sql'=>$sql,
            'params'=>$params
        ];
    }




    public function replace()
    {
        $result = $this->insert();
        $result['sql'] = 'REPLACE'.substr($result['sql'],6);
        return $result;
    }

    public function update()
    {
        $column = [];
        foreach ($this->data as $field => $value){
            $key = ":qpi{$this->qpi}";
            $column[] = "{$field} = {$key}";
            $params[$key] = $value;
            $this->qpi++;
        }
        $placeholder = implode(',',$column);
        $table = $this->parseFrom();
        $where = $this->parseWhere();
        $sql  = "UPDATE {$table} SET {$placeholder} {$where['where']} ";
        return [
            'sql'=>$sql,
            'params'=>array_merge($params,$where['params'])
        ];
    }

    public function delete()
    {
        $table = $this->parseFrom();
        $where = $this->parseWhere();
        $sql  = "DELETE FROM {$table} {$where['where']}";
        return [
            'sql'=>$sql,
            'params'=>$where['params']
        ];
    }

    public function one()
    {
        $table = $this->parseFrom();
        $where = $this->parseWhere();
        $field = is_null($this->field) ? '*' :  is_array($this->field) ? implode(',',$this->field) : $this->field;
        $sql = "SELECT {$field} FROM {$table} WHERE {$where['where']} LIMIT 1";
        return [
            'sql'=>$sql,
            'params'=>$where['params']
        ];
    }

    public function all()
    {
        $table = $this->parseFrom();
        $where = $this->parseWhere();
        $field = is_null($this->field) ? '*' :  is_array($this->field) ? implode(',',$this->field) : $this->field;
        $limit = $this->limit();
        $sql = "SELECT {$field} FROM {$table} WHERE {$where['where']} {$limit}";
        return [
            'sql'=>$sql,
            'params'=>$where['params']
        ];
    }

    public function count($field = '*')
    {
        $table = $this->parseFrom();
        $where = $this->parseWhere();
        $field = "COUNT({$field})";
        $sql = "SELECT {$field} FROM {$table} WHERE {$where['where']}";
        return [
            'sql'=>$sql,
            'params'=>$where['params']
        ];
    }

    public function max($field)
    {
        $table = $this->parseFrom();
        $where = $this->parseWhere();
        $field = "MAX({$field})";
        $sql = "SELECT {$field} FROM {$table} WHERE {$where['where']}";
        return [
            'sql'=>$sql,
            'params'=>$where['params']
        ];
    }

    public function min($field)
    {
        $table = $this->parseFrom();
        $where = $this->parseWhere();
        $field = "MIN({$field})";
        $sql = "SELECT {$field} FROM {$table} WHERE {$where['where']}";
        return [
            'sql'=>$sql,
            'params'=>$where['params']
        ];
    }

    public function avg($field)
    {
        $table = $this->parseFrom();
        $where = $this->parseWhere();
        $field = "AVG({$field})";
        $sql = "SELECT {$field} FROM {$table} WHERE {$where['where']}";
        return [
            'sql'=>$sql,
            'params'=>$where['params']
        ];
    }

    public function sum($field)
    {
        $table = $this->parseFrom();
        $where = $this->parseWhere();
        $field = "SUM({$field})";
        $sql = "SELECT {$field} FROM {$table} WHERE {$where['where']}";
        return [
            'sql'=>$sql,
            'params'=>$where['params']
        ];
    }
    protected function parseInsertData()
    {

        $stack = [];
        $columns = [];
        $fields = [];
        $map = [];

        //转换为二维数组
        $datas = is_array(current($this->data)) ? $this->data : [$this->data];

        foreach ($datas as $data)
        {
            foreach ($data as $key => $value)
            {
                $columns[] = $key;
            }
        }

        $columns = array_unique($columns);

        foreach ($datas as $data)
        {
            $values = [];

            foreach ($columns as $key)
            {
                $map_key =$this->mapKey();

                $values[] = $map_key;

                if (!isset($data[ $key ]))
                {
                    $map[ $map_key ] = [null, PDO::PARAM_NULL];
                }
                else
                {
                    $value = $data[ $key ];

                    switch (gettype($value))
                    {
                        case 'NULL':
                            $map[ $map_key ] = [null, PDO::PARAM_NULL];
                            break;

                        case 'array':
                            $map[ $map_key ] = [
                                strpos($key, '[JSON]') === strlen($key) - 6 ?
                                    json_encode($value) :
                                    serialize($value),
                                PDO::PARAM_STR
                            ];
                            break;

                        case 'object':
                            $map[ $map_key ] = [serialize($value), PDO::PARAM_STR];
                            break;

                        case 'resource':
                            $map[ $map_key ] = [$value, PDO::PARAM_LOB];
                            break;

                        case 'boolean':
                            $map[ $map_key ] = [($value ? '1' : '0'), PDO::PARAM_BOOL];
                            break;

                        case 'integer':
                        case 'double':
                            $map[ $map_key ] = [$value, PDO::PARAM_INT];
                            break;

                        case 'string':
                            $map[ $map_key ] = [$value, PDO::PARAM_STR];
                            break;
                    }
                }
            }

            $stack[] = '(' . implode($values, ', ') . ')';
        }

        foreach ($columns as $key)
        {
            $fields[] = $this->columnQuote(preg_replace("/(^#|\s*\[JSON\]$)/i", '', $key));
        }

        return $this->exec('INSERT INTO ' . $this->tableQuote($table) . ' (' . implode(', ', $fields) . ') VALUES ' . implode(', ', $stack), $map);
    }
    protected function parseFrom()
    {
        return $this->table;
    }
    protected function parseLimit()
    {
        $limit = is_array($this->limit) ? implode(',',$this->limit) : $this->limit;
        return "LIMIT {$limit}";
    }
    protected function parseWhere()
    {
        if(is_string($this->where)){
            return [
                'where'=>$this->where,
                'params'=>$this->params
            ];
        }

        $column = [];
        foreach ($this->data as $field => $value){
            $key = ":qpi{$this->qpi}";
            $column[] = "{$field} = {$key}";
            $params[$key] = $value;
            $this->qpi++;
        }
        $where = 'WHERE '.implode(' AND ',$column);
        return [
            'where'=>$where,
            'params'=>$params
        ];
    }

    protected function mapKey()
    {
        return ':MeDoOmEdOo_' . $this->guid++;
    }

}